<?php
/**
 * basic_filterx
 *
 * @author alex_ez
 */
abstract class basic_filterx extends basic_formx {
    
	protected $field_template = "<div:divatts>\n:before:element\n:inline-error\n:after\n</div>:extra\n\n";
	protected $fields = array();
	protected $buttons = array();
	protected $default_classes = array(
			'text' => 'textbox',
			'password' => 'textbox',
			'file' => 'textbox',
			'textarea' => 'textarea',
			'multiselect' => 'select',
			'select' => 'select',
			'radio' => 'radio',
			'checkbox' => 'checkbox',
			'reset' => 'button',
			'submit' => 'button',
			'button' => 'button',
			'_div' => 'form-field column',
			
			'date' => 'textbox datebox',
	);

	protected $nonce_action = 'filter';
	protected $url = '';
	protected $form_prefix = 'filter';
	protected $form_method = 'get';
	protected $multipart = false;

	protected $options = array( );

	/**
	 * limited
	 * default value, list, and key
	 */
	private $limit = 1; // default value
	private $limits = array( 0, 20, 50, 200, 1000 );
	private $limitkey = '__limit';



	/**
	 * Display for filter form
	 */
	public function display($submit_text = false, $atts = array()) {

		$this ->buttons[] =
			array(
				'type' => 'submit',
				'class' => 'inline',
				'element_class' => 'button button-apply',
				'element_name' => null,
				'value' => __('Apply')
			);
		$this ->buttons[] =
			array(
				'type' => 'reset',
				'class' => 'inline',
				'element_class' => 'button button-reset',
				'element_name' => null,
				'value' => __('Reset')
				);
		$this ->buttons[] =
			array(
				'type' => 'button',
				'class' => 'inline',
				'element_class' => 'button button-clear',
				'element_name' => null,
				'element_onclick' => "javascript:window.location='./';",
				'value' => __('Clear'),
				'extra' => '<br class="clear" />'
			);
		
		$r = parent::display(false, array('class' => 'form-filter'));
		$r = '<div class="form-filter">'.$r.'</div>';

		return $r;
	}
	
	public function set_fields($fields) {

		$r = parent::set_fields($fields);
		
		$this ->fields[$this->limitkey] = array(
			'type' => 'select',
			'element_class' => 'select',
			'label' => __('Quantity'),
			'list' => array_filter( $this ->limits )
			);

		return $r;
	}

	public function get_postdata( $k = null ) {

		$r = parent::get_postdata( $k );
		
		if( is_array($r) && isset($r[$this->limitkey]) )
			unset( $r[$this->limitkey] );
		
		return $r;
	}


	public function get_where( )
	{
		$data = array( );
		$fs = _a::simplify( $this ->fields(), 1 ); // raw fields array
		//$q = @$this->options['mode']['strictwhere']?'':'~'; // qualifier
		$q = '~';

		//var_dump( $fs ); echo '<hr/>';
		
		//var_dump( $this ->get_postdata( ) );
		//var_dump( _a::simplify( $this ->get_postdata( ) ) );
		$postdata = array_filter( _a::simplify( $this ->get_postdata( ) ), 'strlen' );
		//var_dump( $postdata );

		// prepare array to compile
		$data = array( );
		foreach( $postdata as $k => $v )
		{
			$field_key = array_traverse_find( $k, $fs );
			$field = array_traverse( $field_key, $fs );
			
			$field_subkey = substr( $k, strlen( $field_key ) );
			$field_subkey = explode( '[', str_replace( ']', '', $field_subkey ) );
			$field_subkey = array_filter( array_map( 'trim', $field_subkey ) );
			$field_subkey = array_shift( $field_subkey ) . (empty($field_subkey)?'':('[' . implode( '][', $field_subkey ) . ']'));
			
			array_traverse_set( $field_subkey, $data[$field_key], $v );
			//array_traverse_set( $k );/
			//$data[$field_key] = $v;
		}
		//echo '<hr/><hr/>'; var_dump( $data ); echo '<hr/><hr/>';

		// dates
		$dtf =	array( 'datetime' => 'Y-m-d H:i:s', 'date' => 'Y-m-d', 'time' => 'H:i:s', 'month' => 'Y-m-01' );
		$min =	array( 'datetime' => '0000-00-00 00:00:00', 'date' => '0000-00-00', 'time' => '00:00:00', 'month' => '0000-00-00' );
		$max =	array( 'datetime' => '9999-12-31 23:59:59', 'date' => '9999-12-31', 'time' => '23:59:59', 'month' => '9999-12-31' );
		
		// go on!
		$r = array( );
		foreach( $data as $k => $v )
		if( !is_null( $v ) && $v !== "" )
		{
			$field = array_traverse( $k, $fs );
			if( empty($field) )
				continue;
			
			$operator = null;
			
			$type = $field['type'];
			switch( $type )
			{
			case 'list':
			case 'select':
			case 'radio':
				//if( !isset( $fs[$k]['values'][$v] ) ) continue 2;
				break;
			case 'date':
			case 'time':
			case 'datetime':
			case 'month':
				// @ or from+to
				//if( !@$fs[$k]['period'] ) {
				$v = @date_format( date_create( $v ), $dtf[$type] ); if( $v===false ) continue 2;
				/*} else {
				$vf = mb_strlen($v['from']) ? @date_format( date_create( $v['from'] ), $dtf[$type] ) : false;
				$vt = mb_strlen($v['to']) ? @date_format( date_create( $v['to'] ), $dtf[$type] ) : false;
				if( $vf===false && $vt === false ) continue 2;
				$v = array( $vf===false ? $min[$type] : $vf, $vt===false ? $max[$type] : $vt ); $operator = '^';
				}*/
				break;
			case 'date_period':
			case 'time_period':
			case 'datetime_period':
			case 'month_period':
				$type = str_replace( '_period', '', $type );
				
				$vf = mb_strlen(@$v['from']) ? @date_format( date_create( $v['from'] ), $dtf[$type] ) : false;
				$vt = mb_strlen(@$v['to']) ? @date_format( date_create( $v['to'] ), $dtf[$type] ) : false;
				
				if( $vf === false && $vt === false ) continue 2;
				$v = array(
					$vf===false ? $min[$type] : $vf,
					$vt===false ? $max[$type] : $vt );
				$operator = '^';
				break;
			}
			
			$k .= _::pick( $operator, ($type!='number'&&$type!='list'&&$type!='radio') ? $q : '' );
			$r[$k] = $v;
		}

		return $r;
	}




	public function get_query( $addon = null )
	{
		$fid = $this->form_prefix;
		$data = array( );

		$data[$fid][$this->limitkey] = $this ->get_limit( );

		$fs = $this ->fields( );

		foreach( $this ->get_postdata( ) as $k => $v )
		if( !is_null( $v ) && $v !== "" )
			$data[$fid][$k] = $v;

		$data += (array)($addon);

		return http_build_query( $data, 'flags' );
	}

	public function get_limit( )
	{
		$r = $this ->get_postdata( $this ->limitkey );
		//var_dump( $r );

		if( !isset( $this ->limits[ $r ] ) ) $r = $this ->limit;
		if( !isset( $this ->limits[ $r ] ) ) $r = 1;

		return $r;
	}

	public function get_limit_value( )
	{
		return $this ->limits[ $this ->get_limit( ) ];

		return (int)(( isset( $this ->data[ $this ->limitkey ] ) && isset( $this ->limits[ $this ->data[ $this ->limitkey ] ] ) )
			? $this ->limits[ $this ->data[ $this ->limitkey ] ]
			: reset( $this ->limits ));
	}




	/**
	 * Options...
	 */
	

	/**
	 * set option
	 *
	 * @param string $k
	 * @param mixed $v
	 * @return this
	 */
	public function set_option( $k, $v )
	{
		$k = mb_strtolower( $k );
		if( $k == 'mode' )
		{
			if( !is_string( $v ) ) return;
			$modes = array_map( 'trim', array_map( 'strtolower', explode(',',$v) ) );

			foreach( array_filter( $modes ) as $vk )
				$this ->options[ $k ][ ltrim( $vk, ' -!' ) ] = (strpos( '-!', $vk[0] ) === false);
		}
		elseif( $k == 'method' )
			$this ->options[ $k ] = strtolower( $v );
		elseif( $k == 'limits' )
		{
			$this ->limits = array_filter( array_map( 'intval', explode( ',', ','.$v ) ) );
		}
		else
			$this ->options[ $k ] = $v;
		
		return $this;
	}

	/**
	 * set options array
	 *
	 * @param array $a
	 * @return this
	 */
	public function set_options( $a )
	{
		if( !is_array( $a ) ) return;

		foreach( $a as $k => $v )
			$this ->set_option( $k, $v );
		
		return $this;
	}

	/**
	 * get options
	 *
	 * @param string $mode
	 * @return mixed
	 */
	public function options( $mode = null )
	{
		switch( $mode )
		{
		case 'json':
			return json::encode( $this ->options );
		case 'serialize':
			return serialize( $this ->options );
		}
		
		return $this ->options;
	}





	/**
	 * Back-compatibility
	 */
	public function setOptions( $a )
	{
		return $this ->set_options( $a );
	}

	public function setOption( $k, $v )
	{
		return $this ->set_option( $k, $v );
	}

	public function getOptions( )
	{
		return $this ->options( 'array' );
	}





	/**
	 * Custom field types
	 */
	protected function render_date_period($field, $input_atts) {
		$r = '';
		$id = $input_atts['id'];
		$name = $input_atts['name'];
		
		$input_atts['type'] = 'text';
		$input_atts['class'] = $this ->default_class('date');
		
		$input_atts['id'] = $id . '_from';
		$input_atts['name'] = $name . '[from]';
		$r .= $this->_render_input($field, $input_atts);
		
		$input_atts['id'] = $id . '_to';
		$input_atts['name'] = $name . '[to]';
		$r .= $this->_render_input($field, $input_atts);

		return $r;
	}


	/**
	 * Custom field types
	 */
	protected function render_date($field, $input_atts) {
		$input_atts['type'] = 'text';
		return $this->_render_input($field, $input_atts);
	}
}

